package com.example.design_pattern.adapter;

// 本案例演示的是适配器设计模式

// 目标接口。也就是客户端期待的接口
interface Target {
    void request();
}

// 需要适配的类（被适配者）。需要被转换为Target接口。
class Adaptee {
    public void specificRequest() {
        System.out.println("Adaptee's specificRequest method is called");
    }
}

// 适配器类。做具体转换逻辑的。
class Adapter implements Target {
    private Adaptee adaptee; // 被适配者

    // 构造函数
    public Adapter(Adaptee adaptee) {
        // 构造函数调用的时候，把被适配者保存到适配器类的实例对象里面。
        this.adaptee = adaptee;
    }

    // 就是在这里做转换的。
    // 因为客户端要调用的是request方法。所以，我们的适配器类要实现目标类，这样才能实现目标方法：request方法。
    @Override
    public void request() {
        // 外面的名字叫request方法。因为本来就是重写实现的目标类的放啊嘛。
        // 但是在里面实际调用的是被适配器需要被适配的方法。
        adaptee.specificRequest();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 被适配类的实例对象
        Adaptee adaptee = new Adaptee();
        // 把被适配对象adaptee交给适配器加工：new Adapter(adaptee);
        // 加工好之后，返回的就是一个适配器类的实例对象。但是由于Adapter implements了Target，所以可以用Target接口类型接收。
        Target target = new Adapter(adaptee);
        // 通过适配器对象，来调用目标放啊。
        target.request();
    }
}

// 在这个例子中，Target 是客户端所期待的接口，
// Adaptee 是需要被适配的类，而 Adapter 则是适配器类，用于将 Adaptee 的接口转换成 Target 的接口。
// 客户端代码通过 Target 接口调用 request() 方法，实际上会委托给 Adaptee 中的 specificRequest() 方法执行。


// 适配器设计模式一般适用什么场景
// 适配器设计模式通常在以下场景中使用：
//1. **集成现有接口**: 当需要集成一个已有的类或接口，并且其接口与现有系统的接口不兼容时，可以使用适配器模式来创建一个适配器，使得新接口能够与现有系统进行交互。
//2. **解耦**: 适配器模式可以帮助解耦客户端与被适配对象之间的耦合关系，使得它们之间的交互更加灵活。
//3. **第三方库使用**: 当需要使用一个第三方库，但其接口与当前系统不兼容时，可以通过适配器模式来将第三方库的接口适配成系统所需的接口。
//4. **接口升级**: 当系统需要对现有接口进行修改或升级时，可以通过适配器模式来保留原有接口，并提供新的适配器接口，以确保对现有客户端的兼容性。
//总的来说，适配器模式适用于需要将一个接口转换成另一个接口，或者需要与不兼容的接口进行交互的场景。


// Spring MVC中的HandlerAdapter就是适配器模式的应用，用于处理不同类型的请求。
